﻿using System.Text;
using System.Text.Json;

using GCC.Container.Abstracts;
using GCC.Container.LogProviders;

using LuanNiao.JsonConverterExtends;

using Microsoft.Extensions.Caching.Distributed;

namespace GCC.Container.Cache
{
    /// <summary>
    /// 缓存管理对象
    /// </summary>
    public class Manager
    {
        /// <summary>
        /// 日志
        /// </summary>
        private static readonly AbsGCCLogger? _logger = GCCLoggerProvider.Instance?.CreateLogger<Manager>();
        /// <summary>
        /// 所有的缓存客户端
        /// </summary>
        private readonly Dictionary<int, List<CacheInstance>> _allClient = new();
        /// <summary>
        /// 所有的优先级
        /// </summary>
        private List<int> _allPriority = new();
        /// <summary>
        /// 是否锁定
        /// </summary>
        private bool _locked;

        /// <summary>
        /// 推送一个新的缓存实例
        /// </summary>
        /// <param name="instance">实例</param>
        public void PushNewClient(CacheInstance instance)
        {
            if (this._locked)
            {
                return;
            }

            if (instance is null || instance.Instance is null)
            {
                return;
            }
            lock (_allClient)
            {
                if (_allClient.ContainsKey(instance.Priority))
                {
                    _allClient[instance.Priority].Add(instance);
                }
                else
                {
                    _allClient[instance.Priority] = new List<CacheInstance>() { instance };
                }
                _allPriority = _allClient.Keys.OrderByDescending(item => item).ToList();
            }
        }

        /// <summary>
        /// 获取当前系统设置的所有的优先级
        /// </summary>
        /// <returns></returns>
        public int[] AllPriority()
        {
            return _allPriority.ToArray();
        }

        /// <summary>
        /// 锁定
        /// </summary>
        public void Lock()
        {
            this._locked = true;
        }
        /// <summary>
        /// 解锁,可能会造成多线程问题
        /// </summary>
        public void UnLock()
        {
            this._locked = false;
        }
        /// <summary>
        /// 根据key获取某一个缓存,自己用优先级判定
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <param name="key">key</param>
        /// <param name="cancellationToken">取消token</param>
        /// <returns>从缓存获取的值,可能为空</returns>
        public async Task<T> TryGet<T>(string key, CancellationToken cancellationToken = default)
        {
            foreach (var priorityItem in _allPriority)
            {
                foreach (var item in this._allClient[priorityItem])
                {
                    if (item.Available)
                    {
                        try
                        {
                            var res = await item.Instance.GetAsync(key, cancellationToken);
                            if (res is not null)
                            {
                                return JsonSerializer.Deserialize<T>(res, CommonSerializerOptions.CamelCaseChineseNameCaseInsensitive)!;
                            }
                        }
                        catch (Exception ex)
                        {
                            _logger?.Information($"Try get cahce use key{key} error.", exception: ex);
                        }
                    }

                }
            }
            return default;
        }

        /// <summary>
        /// 根据Key获取,如果获取不到则新增
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="key">key</param>
        /// <param name="onSet">当获取不到的时候从哪获取值</param>
        /// <param name="settings">过期时间</param>
        /// <param name="cancellationToken">取消token</param>
        /// <returns></returns>
        public async Task<T> GetOrSet<T>(string key, Func<Task<T>> onSet, CacheItemSettings settings, CancellationToken cancellationToken = default)
        {
            var res = await TryGet<T>(key, cancellationToken);
            if (res is not null)
            {
                return res;
            }
            else
            {
                var data = await onSet();
                await Set<T>(key, data, settings, cancellationToken);
                return data;
            }

        }

        /// <summary>
        /// 设置一个值到缓存
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="key">key</param>
        /// <param name="data">数据</param>
        /// <param name="settings">过期时间</param>
        /// <param name="cancellationToken">取消token</param>
        public async Task Set<T>(string key, T data, CacheItemSettings settings, CancellationToken cancellationToken = default)
        {

            foreach (var priorityItem in _allPriority)
            {
                foreach (var item in this._allClient[priorityItem])
                {
                    if (item.Available)
                    {
                        try
                        {
                            var bytes = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(data, CommonSerializerOptions.CamelCaseChineseNameCaseInsensitive));
                            await item.Instance.SetAsync(key, bytes,
                                new DistributedCacheEntryOptions()
                                {
                                    AbsoluteExpiration = settings.AbsoluteExpiration,
                                    AbsoluteExpirationRelativeToNow = settings.AbsoluteExpirationRelativeToNow,
                                    SlidingExpiration = settings.SlidingExpiration,
                                }, cancellationToken);
                            if (!settings.SaveToAll)
                            {
                                return;
                            }
                        }
                        catch (Exception ex)
                        {
                            _logger?.Information($"Try set cahce use key{key} error.", exception: ex);
                        }
                    }

                }
            }
        }

        /// <summary>
        /// 移除一个缓存
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="cancellationToken">取消token</param>
        public async Task Remove(string key, CancellationToken cancellationToken = default)
        {
            foreach (var priorityItem in _allPriority)
            {
                foreach (var item in this._allClient[priorityItem])
                {
                    if (item.Available)
                    {
                        try
                        {
                            await item.Instance.RemoveAsync(key, cancellationToken);
                        }
                        catch (Exception ex)
                        {
                            _logger?.Information($"Try remove cahce use key{key} error.", exception: ex);
                        }
                    }

                }
            }
        }

        /// <summary>
        /// 刷新一下某个缓存
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="cancellationToken">取消token</param>
        public async Task Refresh(string key, CancellationToken cancellationToken = default)
        {
            foreach (var priorityItem in _allPriority)
            {
                foreach (var item in this._allClient[priorityItem])
                {
                    if (item.Available)
                    {
                        try
                        {
                            await item.Instance.RefreshAsync(key, cancellationToken);
                        }
                        catch (Exception ex)
                        {
                            _logger?.Information($"Try refresh cahce use key{key} error.", exception: ex);
                        }
                    }
                }
            }
        }


    }
}
